package com.sunchangming.stmdb;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 锁
 * 
 * @author cm
 * 
 */
public final class Lockey implements java.lang.Comparable<Lockey> {
	private final String name;
	private final Object key;

	private ReentrantLock lock;

	/**
	 * 
	 * @param name
	 *            lock name
	 * @param key
	 *            被保护的对象。注意它的equals、compareTo、hashcode是否被正确实现。
	 */
	Lockey(String name, Object key) {
		this.name = name;
		this.key = key;
	}

	final void alloc() {
		if (null != lock)
			throw new XError("com.sunchangming.xc : xlock alloc");
		lock = new ReentrantLock();
	}

	public final boolean isHeldByCurrentThread() {
		return lock.isHeldByCurrentThread();
	}

	public final String getName() {
		return name;
	}

	public final Object getKey() {
		return key;
	}

	public final void unlock() {
		lock.unlock();
	}

	public final boolean tryLock() {
		return lock.tryLock();
	}

	public final boolean tryLock(long milliseconds) {
		return tryLock(milliseconds, TimeUnit.MILLISECONDS);
	}

	/**
	 * 不可打断的锁请求。
	 */
	final void _lock() {
		lock.lock();
	}

	/**
	 * @throws XLockDead
	 *             被angel打断
	 * @throws XLockInterrupted
	 *             被其它的方式打断
	 */
	public final void lock() {
		try {
			lock.lockInterruptibly();
		} catch (final InterruptedException ex) {
			//TODO:检查是不是被dead lock detector 打断的。
			throw new XLockInterrupted(this.toString());
		}
	}

	public final boolean tryLock(long time, TimeUnit unit) {
		try {
			return lock.tryLock(time, unit);
		} catch (final InterruptedException ex) {
			// tryLock 肯定不会造成死锁．需要确认findDeadlockedThreads如何判断的。
			// 现在先不看作死锁。
			throw new XLockInterrupted(this.toString());
		}
	}

	@Override
	public int compareTo(Lockey arg0) {
		int rc = 0;

		rc = name.compareTo(arg0.name);
		if (rc != 0)
			return rc;

		@SuppressWarnings("unchecked")
		final Comparable<Object> k1 = (Comparable<Object>) key;
		rc = k1.compareTo(arg0.key);
		if (rc != 0)
			return rc;

		return 0;
	}

	@Override
	public int hashCode() {
		return name.hashCode() ^ key.hashCode();
	}

	@Override
	public boolean equals(Object obj) {
		if (obj instanceof Lockey) {
			final Lockey o = (Lockey) obj;
			return key.equals(o.key) && getName().equals(o.getName());
		}
		return false;
	}

	@Override
	public String toString() {
		return key.toString() + "@" + name;
	}
}
